package server.network;

import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import common.Log;

public class Server_Reception extends Thread{

	private ServerSocket m_serveur_socket;
	private Server m_serveur;
	private Server_Command m_server_commands;
	private Socket m_reception;
	/**
	 * La taille du buffer par défaut pour la réception du fichier.
	 */
	private final static int BUFF_SIZE = 1024;

	public Server_Reception(int port, Server serveur, Server_Command serveur_commands){
		try{
			m_serveur_socket = new ServerSocket(port);
			m_serveur = serveur;
			m_server_commands = serveur_commands;
		}catch(IOException e){
			e.printStackTrace();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	public void run(){

		try {
			m_reception = m_serveur_socket.accept();
		} catch (IOException e) {
			e.printStackTrace();
		}
		while(true){
			try {
				receiveFiles();
			} catch (IOException e) {
				e.printStackTrace();
			}
			m_server_commands.send_tree_model();
		}

	}

	/**
	 * Réceptionne un ou plusieurs fichiers envoyés à la suite.
	 * @throws IOException
	 */
	public void receiveFiles() throws IOException
	{
		DataInputStream _socketInputStream = new DataInputStream(m_reception.getInputStream());

		OutputStream _fileOutputStream;
		int readBytes;
		long fileSize;
		String filePath;
		long nbrOfFullPackets;
		long lastPacketSize;

		// Attendre pour tous les fichiers
		while (true)
		{
			// Initialisation
			readBytes = 0;
			fileSize = 0;
			filePath = null;
			nbrOfFullPackets = 0;
			lastPacketSize = 0;

			// Récupérer la taille du fichier
			fileSize = _socketInputStream.readLong();

			// Récupérer le chemin absolu du fichier sur la machine cliente
			filePath = _socketInputStream.readUTF();

			// Récupération du chemin définitif du fichier sur le serveur
			filePath = GetServerFilePath(filePath);

			// Création du fichier sur le serveur.
			_fileOutputStream = new FileOutputStream(m_serveur.get_racine_path() + "/" + filePath);

			// La taille du dernier packet à recevoir.
			lastPacketSize = fileSize % BUFF_SIZE;

			// Récupération du nombre complet de buffers envoyés
			nbrOfFullPackets = (fileSize - lastPacketSize) / BUFF_SIZE;

			// Buffer de lecture du flux d'entrée du socket server.
			byte _buffer[] = new byte[BUFF_SIZE];

			// Pour tous les paquets complets.
			for (int i=0; i<nbrOfFullPackets; i++)
			{
				// Récupération du packet depuis le flux d'entrée du socket.
				readBytes = _socketInputStream.read(_buffer);

				// Des données ont été reçues
				if (readBytes != -1)
				{
					// Ecrire le paquet de données dans le fichier
					_fileOutputStream.write(_buffer, 0, readBytes);
				}
			}

			// Ecrire le dernier paquet de données dans le fichier
			if (lastPacketSize != 0)
			{
				// Déclaration d'un nouveau buffer de la taille du dernier paquet
				_buffer = new byte[(int) lastPacketSize];

				// Récupération du packet depuis le flux d'entrée du socket.
				readBytes = _socketInputStream.read(_buffer);

				// Des données ont été reçues
				if (readBytes != -1)
				{
					// Ecrire le paquet de données dans le fichier
					_fileOutputStream.write(_buffer, 0, readBytes);
				}
			}

			Log.write_log(m_serveur.get_racine_path(), "File copy", filePath + " copié avec succès.");

			// On ferme le flux d'écriture du fichier.
			_fileOutputStream.close();
			_fileOutputStream = null;

			// Il ne reste plus de fichiers à recevoir.
			if (_socketInputStream.available() == 0)
			{
				// On quitte la boucle d'attente des fichiers
				break;
			}
		}
	}

	/**
	 * Récupère le chemin absolut du fichier sur le serveur à partir du chemin absolut du fichier sur le client.
	 * @param clientFilePath
	 * Le chemin absolut du fichier sur le client.
	 * @return
	 * Le chemin absolut du fichier sur le serveur.
	 */
	public static String GetServerFilePath(String clientFilePath)
	{
		return clientFilePath;
	}

	public boolean close(){
		try{
			m_serveur_socket.close();
			if(m_serveur_socket.isClosed())
				return true;
		}catch(IOException e){
			e.printStackTrace();
		}catch(Exception e){
			e.printStackTrace();
		}
		return false;
	}

	public ServerSocket get_serveur() {
		return m_serveur_socket;
	}

	public void set_serveur(ServerSocket serveur) {
		this.m_serveur_socket = serveur;
	}

	public Socket get_reception() {
		return m_reception;
	}

	public void set_reception(Socket reception) {
		this.m_reception = reception;
	}
}
